feat(claude-ops): add inventory skill enumerating the invocable surface - #2313
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Answers "what can this machine actually invoke, and where did each thing come from" in one read-only report: built-in CLI commands with aliases and hidden/gated markers, bundled skills, and every component of every installed plugin across all marketplaces. The built-in and bundled surfaces are read from the shipped binary because upstream publishes no built-in command list — docs/en/slash-commands and docs/en/skills return byte-identical markdown since commands were merged into skills — so no documentation source is complete for them. Plugin components are read from disk. The two sources stay separated in the report because they are evidence of different quality. Extraction resolves at runtime what changes between releases: registrar names come from the bundle's export maps rather than a hardcoded minified identifier, the bundle is found by export-name anchor rather than section layout, and command fields are read by brace depth rather than a text window, since adjacent minified literals otherwise bleed into one another. Python 3.11+ only — no strings, jq, or PowerShell. Every run carries an integrity verdict, because the failure that matters is not a crash but a clean-looking short list. Canary commands, a minimum resolved-to-token ratio, a sweep for unrecognised registrar-shaped exports, and the resolved-versus-seen gap on bundled skills each turn a quiet shortfall into a stated one; a degraded run reports counts as floors. --self-check exits 0/1/2 for use as a CI gate or scheduled drift check. Filters accept a flag or the equivalent sentence; one extraction feeds every view. 25 hermetic tests cover the brace reader, constant resolution, and each integrity verdict against synthetic fixtures, so the suite does not change its answer when the installed CLI updates. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1292851 to
eb626bf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12928518b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude finished @kyle-sexton's task in 1m 25s —— View job Security Review — PR #2313
Result: No security issues foundI reviewed only the files changed in this PR ( What the script does, from a trust-boundary perspective:
Specific things I checked and ruled out:
This is a read-only, local-only diagnostic tool with no new injection, authorization, or secret-handling surface. Nothing to flag. |
|
Claude finished @kyle-sexton's task in 4m 30s —— View job Claude's reviewTodo list
SummaryReviewed the changed files for correctness, error handling, test coverage, and maintainability (this repo has a
Both come with a What I couldn't verify: Bash execution wasn't available in this review environment, so I could not run Otherwise: the extraction design (runtime registrar discovery, brace-depth field resolution for commands, integrity verdict with canaries/yield-ratio/registrar-sweep) is careful and well-documented; the manifest/changelog/catalog/cheat-sheet updates are mechanical and consistent with the new skill. |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
Three spellchecker hits and two missing exec bits, all in the new inventory skill: - Dropped the illustrative `getBundledSkills:()=>dFo` half of the export-map snippet in reference/extraction.md. The identifier is a verbatim minified name and reads as a typo; only the registerBundledSkill mapping is load-bearing for the point the snippet makes. - Renamed the synthetic fixture identifier lFo to dvz in test_inventory.py and spelled misattribute without the hyphen. - Marked inventory.py and test_inventory.py executable, matching the exec bit the sibling audit-install-state scripts already carry. No behaviour change; the 25 tests still pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 50s —— View job Security Review — PR #2313
Result: No security issues foundReviewed all 9 files changed in this PR (current HEAD Trust-boundary analysis of
This is a read-only, local-only diagnostic tool with no new injection, authorization, or secret-handling surface. (Note: the correctness/logic findings already raised by Codex and the earlier Claude review pass in this thread — field-window bleed in |
Automated exact-file synchronization from [`melodic-software/standards@117116ab79ef13c355bafc96c597682c225594d0`](melodic-software/standards@117116a) (requested ref `main`). No linked issue — recurring automated distribution, not tied to a tracked change. Managed component mappings applied to `melodic-software/claude-code-plugins`: - **actionlint**: `.github/actionlint.yaml` → `.github/actionlint.yaml` (mode `100644`) - **agent-orientation**: `components/agent-orientation/orientation.md` → `AGENTS.md` (mode `100644`) - **editorconfig-checker**: `.editorconfig-checker.json` → `.editorconfig-checker.json` (mode `100644`) - **gitleaks**: `.gitleaks.toml` → `.gitleaks.toml` (mode `100644`) - **lychee**: `lychee.toml` → `lychee.toml` (mode `100644`) - **markdownlint**: `.markdownlint-cli2.jsonc` → `.markdownlint-cli2.jsonc` (mode `100644`) - **node-runtime**: `.node-version` → `.node-version` (mode `100644`) - **path-detection-guardrails**: `components/path-detection/machine-path-patterns.sh` → `plugins/guardrails/lib/path-detection/machine-path-patterns.sh` (mode `100644`) - **pr-convention-policy**: `components/pr-convention-policy/package-lock.json` → `.github/standards/pr-convention-policy/package-lock.json` (mode `100644`) - **pr-convention-policy**: `components/pr-convention-policy/package.json` → `.github/standards/pr-convention-policy/package.json` (mode `100644`) - **pr-convention-policy**: `components/pr-convention-policy/policy.json` → `.github/standards/pr-convention-policy/policy.json` (mode `100644`) - **pr-convention-policy**: `components/pr-convention-policy/policy.schema.json` → `.github/standards/pr-convention-policy/policy.schema.json` (mode `100644`) - **pr-convention-policy**: `components/pr-convention-policy/pr-convention-policy.mjs` → `.github/standards/pr-convention-policy/pr-convention-policy.mjs` (mode `100755`) - **pyright**: `components/pyright/pyrightconfig.json` → `.github/standards/pyright/pyrightconfig.json` (mode `100644`) - **repository-text**: `.editorconfig` → `.editorconfig` (mode `100644`) - **repository-text**: `.gitattributes` → `.gitattributes` (mode `100644`) - **review-instructions**: `REVIEW.md` → `REVIEW.md` (mode `100644`) - **runner-policy**: `components/runner-policy/package-lock.json` → `.github/standards/runner-policy/package-lock.json` (mode `100644`) - **runner-policy**: `components/runner-policy/package.json` → `.github/standards/runner-policy/package.json` (mode `100644`) - **runner-policy**: `components/runner-policy/policy.json` → `.github/standards/runner-policy/policy.json` (mode `100644`) - **runner-policy**: `components/runner-policy/policy.schema.json` → `.github/standards/runner-policy/policy.schema.json` (mode `100644`) - **runner-policy**: `components/runner-policy/repository-policy.schema.json` → `.github/standards/runner-policy/repository-policy.schema.json` (mode `100644`) - **runner-policy**: `components/runner-policy/runner-policy.mjs` → `.github/standards/runner-policy/runner-policy.mjs` (mode `100755`) - **shellcheck**: `.shellcheckrc` → `.shellcheckrc` (mode `100644`) - **typos**: `_typos.toml` → `_typos.toml` (mode `100644`) Review and merge this PR normally. Do not hand-edit these managed files downstream; change their standards source instead. ## Related - [`melodic-software/standards@117116ab79ef13c355bafc96c597682c225594d0`](melodic-software/standards@117116a) — source commit this sync distributes. Co-authored-by: melodic-standards-sync[bot] <300666570+melodic-standards-sync[bot]@users.noreply.github.com>
- Build marketplace output from installed_plugins.json installPath records - Merge enabledPlugins with local > project > user precedence - Honor manifest-declared component paths when scanning plugins - Include project .claude skills/agents/hooks/MCP in project_scope_components - Degrade integrity when CLI version cannot be detected from a real bundle - Set executable bits on inventory Python scripts Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
|
Warning Automated security review did not complete — this is an infrastructure failure, not a review verdict. Treat any Claude comment on this PR (including a placeholder like "I'll analyze this and get back to you") as incomplete, not "no findings."
The check is green on purpose, and it is not evidence. It certifies that a security pass ran, and this one did not complete — but the cause is outside this PR's control, so merging is deliberately left unblocked rather than locking every merge for the length of the outage. Nothing was reviewed at this head. Where this check is required, it is satisfied without that evidence; a human should review security-sensitive changes here before merging. Re-run the job to retry the review; a new push also retries it only if the caller's Re-running does NOT help for every class:
|
|
Warning Automated review did not complete — this is an infrastructure failure, not a review verdict. Treat any Claude comment on this PR (including a placeholder like "I'll analyze this and get back to you") as incomplete, not "no findings."
Re-run the job to retry the review. A new push re-triggers this lane only if the caller's |
…age error --self-check returned 2 for a degraded verdict, which is also argparse's exit code for a usage error. A CI gate treating 2 as "degraded, warn" would silently swallow a mistyped flag as a warning instead of failing. Degraded is now 3, leaving 2 to argparse: 0 ok, 1 broken, 2 usage error, 3 degraded. Verified all four against the live build. Also records the 0.30.1 changelog entry covering this and the review findings carried over from #2313, which merged before those fixes landed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cope coverage (#2350) ## Summary Follow-up to #2313, which merged before these fixes landed — auto-merge fired when its checks went green and squashed only the first two commits, so main currently carries the defects below. Six findings, all from the automated review on #2313 and all real: **Correctness** - **Bundled-skill fields could bleed from the next registration.** The extractor read each registration through a fixed 4000-character window — the exact failure mode `build_brace_map` exists to prevent for commands, and the one `reference/extraction.md` names as the thing not to do. A registration omitting a description adopted the following one's. Fields are now bound to their own literal via the brace map; an unmatched brace is counted and surfaced rather than silently skipped. - **Manifest-declared component paths were ignored.** `PLUGIN_COMPONENTS` carried a manifest key per component and a comment claiming the manifest is read before the tree; nothing read it. A declared path *replaces* the default directory, so scanning defaults regardless reported components a plugin does not ship. Dotted keys resolve the `experimental` block. - **`--self-check` lost its diagnostic when no binary was found.** `pick_binary` stores its explanation under `reason`; the self-check path read only `error` and printed a generic message. - **An unreadable CLI version passed silently.** It is itself a drift signal, so it now degrades the verdict rather than skipping the comparison. - **Degraded and argparse's usage error both exited 2.** A CI gate treating 2 as "degraded, warn" would silently swallow a mistyped flag. Degraded is now **3**, leaving 2 to argparse: `0` ok, `1` broken, `2` usage error, `3` degraded. **Coverage** - **Installed plugins and project scope were never read.** Only marketplace catalogs were scanned, so a plugin installed from a marketplace that is no longer cached was invisible. `disk.installed_plugins` now walks the plugin cache, and catalog / installed / enabled are reported as three distinct sets. A project's `.claude` tree contributes skills, agents, and wired hook events that no machine-scope scan sees; `--project-dir` defaults to cwd. Wired hook *events* are reported, never hook scripts on disk — listing an unreferenced script as a hook would repeat the present-versus-active error the skill exists to avoid. ## Test plan - [x] `test_inventory.py` — 31 hermetic tests (was 25), adding field-binding non-bleed, manifest path resolution incl. dotted and array forms, and the version-unknown advisory - [x] One existing fixture corrected: it asserted `ok` against a build the new version check correctly calls `degraded` - [x] Exit codes verified individually against the live build: `0` ok, `1` broken (missing binary, and a non-binary file), `2` usage error, `3` degraded - [x] Negative paths: nonexistent `--binary` (reason preserved in output), mutually exclusive flags, empty config dir, non-binary file - [x] Live run on 2.1.228: 104 built-in commands, 33 bundled skills, `installed_plugins` 67 across 4 marketplaces vs 121 catalog entries — the distinction this PR adds - [x] `check-skill.sh` PASS 0 errors · `check-evals-quality.sh` PASS · portability clean · `validate-plugins.sh` clean · cheat sheet in sync ## Related No linked issue. Direct follow-up to #2313 (merged), addressing that PR's own review comments, which arrived after auto-merge had already squashed and merged it. - `claude-ops` 0.30.0 → 0.30.1. - Still deliberately out of scope, unchanged from #2313: a generic binary-exploration plugin. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
Adds
/claude-ops:inventory— a read-only report answering "what can this machine actually invoke, and where did each thing come from": built-in CLI commands with aliases and hidden/gated markers, bundled skills, and every component of every installed plugin across all marketplaces.Why the binary is read. Upstream publishes no built-in slash-command list.
docs/en/slash-commands.mdanddocs/en/skills.mdreturn byte-identical markdown — commands were merged into skills — so no documentation source is complete for the built-in surface. Plugin components are read from disk. The two sources stay separated in the report because they are evidence of different quality.Why it survives releases. Everything that changes between builds is resolved at runtime: registrar names come from the bundle's export maps (
registerBundledSkill:()=>xu) rather than a hardcoded minified identifier; the bundle is located by export-name anchor rather than section layout; command fields are read by brace depth rather than a text window, since adjacent minified literals otherwise bleed into one another.Why it tells on itself. The failure that matters is not a crash — a renamed export throws and is obvious. It is a new registration path, which returns a clean, confident, short list with no error. Every run therefore carries an integrity verdict (
ok/degraded/broken) fed by canary commands, a minimum resolved-to-token ratio, a sweep for unrecognised registrar-shaped exports, and the resolved-versus-seen gap on bundled skills. Adegradedrun reports counts as floors, not totals.--self-checkprints one verdict line and exits 0/1/2 for use as a CI gate or scheduled drift check, with/claude-ops:changelogas the natural trigger.VALIDATED_AGAINSTrecords the last human-verified build, so a consumer on an older plugin against a newer CLI is told its counts are believed rather than verified.Filters accept either a flag (
--builtin,--plugins,--marketplace <name>,--agents,--hooks,--diff) or the equivalent sentence; one extraction feeds every view.Scope boundary: this inventories capabilities that resolve;
/claude-ops:audit-install-stateinventories files on disk;/claude-ops:pluginskeeps the fleet current;/claude-config:auditowns settings drift. No hooks, no new dependencies, no mutation — the binary is opened read-only and never executed.Test plan
check-skill.sh— PASS, 0 errors, 1 soft warning (209 lines vs 200 target)check-evals-quality.sh— PASS, 0 warnings, 6 eval casescheck-skill-portability.sh— no unexcused coupling tokenscheck-skill-leaf-names.sh—inventoryunique across all 65 pluginsvalidate-plugins.sh+validate-plugin-contracts.mjs— 2317 files, catalog in syncgenerate-cheatsheet.mjs --check— in synctest_inventory.py— 25 hermetic tests, 0.002s, no binary requiredsecurity-reviewcorrectly flagged plugin-backed, 4 marketplaces / 121 plugins, 2.7s--self-checkcorrectly reportsDEGRADED(exit 2) on the live build: 36 bundled-skill registrations seen, 33 resolved, 3 using computed names — the list is reported as a floor rather than a totalUpstream claims were verified from raw markdown endpoints (
curl -sSL .../page.md), not summarizing fetches, and both carry a recheck trigger in the skill body.Related
No linked issue — this skill originated from an ad-hoc session that reverse-engineered the built-in command surface by hand, and the work was captured as a repeatable skill rather than filed as an issue first.
/claude-ops:audit-install-state(files on disk),/claude-ops:plugins(fleet currency),/claude-config:audit(settings drift). This PR adds a fourth object — capabilities that resolve — and cross-links all three from its scope-boundary table.🤖 Generated with Claude Code